﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

namespace blockparser
{
    class Program
    {
        static string neo = "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b";
        static string gas = "0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7";
        static void Main(string[] args)
        {
            Console.WriteLine("Start to Parse.");
            int parseIndex = 0;
            for (; ; parseIndex++)
            {
                var file = "D:\\history10k\\" + parseIndex.ToString("D08") + ".txt";
                if (System.IO.File.Exists(file) == false)
                {

                    break;
                }
                var txt = System.IO.File.ReadAllText(file, System.Text.Encoding.UTF8);
                var json = Newtonsoft.Json.Linq.JObject.Parse(txt);
                ParseOne(json);
            }
            Console.WriteLine("parse count=" + parseIndex);
            ShowResult();

            Console.WriteLine("press any key to exit.");
            Console.ReadLine();
        }

        class VIN
        {
            public string txid;
            public int n;
        }
        class VOUT
        {
            public string asset;
            public System.Numerics.BigInteger value;
            public string address;
        }

        class TX
        {
            public string txid;
            public VOUT[] vout;
            public VIN[] vin;
        }
        static System.Collections.Generic.Dictionary<string, TX> allTrans = new System.Collections.Generic.Dictionary<string, TX>();


        class UserAddr
        {
            public List<string> utxos = new List<string>();
        }

        static Dictionary<string, UserAddr> alladdress = new Dictionary<string, UserAddr>();
        static void ParseOne(JObject json)
        {
            var txs = (JArray)json["tx"];
            foreach (JObject tx in txs)
            {
                var objtx = new TX();
                objtx.txid = (string)tx["txid"];
                var vin = (JArray)tx["vin"];
                var vout = (JArray)tx["vout"];
                objtx.vin = new VIN[vin.Count];
                objtx.vout = new VOUT[vout.Count];
                for (var i = 0; i < vin.Count; i++)
                {
                    objtx.vin[i] = new VIN();
                    objtx.vin[i].txid = (string)vin[i]["txid"];
                    objtx.vin[i].n = (int)vin[i]["vout"];
                }
                for (var i = 0; i < vout.Count; i++)
                {
                    objtx.vout[i] = new VOUT();
                    objtx.vout[i].asset = (string)vout[i]["asset"];
                    var vstr = (string)vout[i]["value"];
                    objtx.vout[i].value = System.Numerics.BigInteger.Parse(vstr);
                    objtx.vout[i].address = (string)vout[i]["address"];

                }
                allTrans[objtx.txid] = objtx;
                ParseOneObj(objtx);
            }
        }
        static void ParseOneObj(TX tx)
        {
            foreach (var vin in tx.vin)
            {
                var coin = allTrans[vin.txid].vout[vin.n];
                var utxoid = vin.txid + "_" + vin.n;
                alladdress[coin.address].utxos.Remove(utxoid);//销毁钱
            }
            for (var n = 0; n < tx.vout.Length; n++)
            {
                var vout = tx.vout[n];
                if (alladdress.ContainsKey(vout.address) == false)
                {
                    alladdress[vout.address] = new UserAddr();
                }
                var utxoid = tx.txid + "_" + n;
                alladdress[vout.address].utxos.Add(utxoid);//加钱
            }
        }
        static void ShowResult()
        {
            Console.WriteLine("have address:" + alladdress.Count);
            Console.WriteLine();
            foreach (var add in alladdress)
            {
                Console.WriteLine("addr=" + add.Key);
                Dictionary<string, System.Numerics.BigInteger> coins = new Dictionary<string, System.Numerics.BigInteger>();
                foreach (var utxo in add.Value.utxos)
                {
                    var words = utxo.Split("_");
                    var txid = words[0];
                    var n = int.Parse(words[1]);
                    var coin = allTrans[txid].vout[n];
                    if (coins.ContainsKey(coin.asset) == false)
                    {
                        coins[coin.asset] = 0;
                    }
                    coins[coin.asset] += coin.value;
                }
                if (coins.Count == 0)
                    Console.WriteLine("  <NoMoney>");
                foreach(var asset in coins)
                {
                    var assetid = asset.Key;
                    if (assetid == neo)
                        assetid = "<NEO>";
                    if (assetid == gas)
                        assetid = "<GAS>";
                    Console.WriteLine("  " + assetid + "=" + asset.Value);
                }
                Console.WriteLine();
            }
        }
    }
}
